package com.uwlaser.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.uwlaser.base.PageInfo;
import com.uwlaser.base.QueryHelpMybatisPlus;
import com.uwlaser.base.impl.CommonServiceImpl;
import com.uwlaser.domain.*;
import com.uwlaser.service.OrderSerialService;
import com.uwlaser.service.PlanOrderService;
import com.uwlaser.service.PlanWorkOrderService;
import com.uwlaser.service.dto.OrderSerialDto;
import com.uwlaser.service.dto.PlanOrderDto;
import com.uwlaser.service.dto.PlanOrderQueryParam;
import com.uwlaser.service.mapper.*;
import com.uwlaser.utils.ConvertUtil;
import com.uwlaser.utils.PageUtil;
import com.uwlaser.utils.enums.DictValueEnum;
import lombok.AllArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;

/**
* @author zk-Qin
* @date 2022-05-11
*/
@Service
@AllArgsConstructor
// @CacheConfig(cacheNames = PlanOrderService.CACHE_KEY)
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class PlanOrderServiceImpl extends CommonServiceImpl<PlanOrderMapper, PlanOrder> implements PlanOrderService {

    // private final RedisUtils redisUtils;
    private final PlanOrderMapper planOrderMapper;

    private final ProductBomMapper productBomMapper;

    private final ProductBomDetailMapper productBomDetailMapper;

    private final ProductModelMapper productModelMapper;

    private final ProductModelLienMapper productModelLienMapper;

    private final PlanWorkOrderService planWorkOrderService;

    private final OrderSerialService orderSerialService;

    @Override
    public PageInfo<PlanOrderDto> queryAll(PlanOrderQueryParam query, Pageable pageable) {
        IPage<PlanOrder> queryPage = PageUtil.toMybatisPage(pageable);
        IPage<PlanOrder> page = planOrderMapper.selectPage(queryPage, QueryHelpMybatisPlus.getPredicate(query));
        return ConvertUtil.convertPage(page, PlanOrderDto.class);
    }

    @Override
    public List<PlanOrderDto> queryAll(PlanOrderQueryParam query){
        return ConvertUtil.convertList(planOrderMapper.selectList(QueryHelpMybatisPlus.getPredicate(query)), PlanOrderDto.class);
    }

    @Override
    public PlanOrder getById(Integer id) {
        return planOrderMapper.selectById(id);
    }

    @Override
    // @Cacheable(key = "'id:' + #p0")
    public PlanOrderDto findById(Integer id) {
        return ConvertUtil.convert(getById(id), PlanOrderDto.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insert(PlanOrderDto resources) {
        PlanOrder entity = ConvertUtil.convert(resources, PlanOrder.class);
        PlanOrder planOrder = new PlanOrder();
        planOrder.setOrderCode(entity.getOrderCode());
        Integer integer = planOrderMapper.selectCount(new QueryWrapper<>(planOrder));
        if(integer > 0){
            throw new RuntimeException("订单号【"+entity.getOrderCode()+"】已存在!");
        }
        return planOrderMapper.insert(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateById(PlanOrderDto resources){
        PlanOrder entity = ConvertUtil.convert(resources, PlanOrder.class);
        int ret = planOrderMapper.updateById(entity);
        PlanOrder planOrder = new PlanOrder();
        planOrder.setOrderCode(entity.getOrderCode());
        Integer integer = planOrderMapper.selectCount(new QueryWrapper<>(planOrder));
        if(integer >= 2){
            throw new RuntimeException("订单号【"+entity.getOrderCode()+"】已存在!");
        }
        return ret;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int removeByIds(Set<Integer> ids){
        // delCaches(ids);
        return planOrderMapper.deleteBatchIds(ids);
    }

    /**
     * 生成工单
     * @param resources
     * @return
     */
    @Override
    public int generate(PlanOrderDto resources) {

        if(!DictValueEnum.ORDER_STATUS_NOT.getValue().equals(resources.getOrderStatus())){
            throw new RuntimeException("当前订单状态不是【"+DictValueEnum.ORDER_STATUS_NOT.getLabel()+"】状态，已经生成过工单了！");
        }
        //生成的工单列表
        List<PlanWorkOrder> planWorkOrders = new ArrayList<>();

        //递归生成工单
        generateWorkOrder(planWorkOrders, resources);

        //如果存在相同型号的工单合并
        List<PlanWorkOrder> addWorkOrders = mergeWorkOrder(planWorkOrders);

        //保存工单
        planWorkOrderService.saveBatch(addWorkOrders);

        //生成P类型的工单序列号记录
        for (PlanWorkOrder addWorkOrder : addWorkOrders) {
            if("P".equals(addWorkOrder.getProductType())){
                OrderSerialDto orderSerial=new OrderSerialDto();
                orderSerial.setProductCode(addWorkOrder.getProductCode());
                orderSerial.setWorkOrderCode(addWorkOrder.getWorkOrderCode());
                orderSerial.setFirstSerial(0);
                orderSerial.setLastSerial(1);
                orderSerial.setTotalSerialCount(0);
                orderSerialService.insert(orderSerial);
            }
        }
        //更新订单状态
        PlanOrder planOrder = new PlanOrder();
        planOrder.setId(resources.getId());
        planOrder.setOrderStatus(DictValueEnum.ORDER_STATUS_CREATE.getValue());
        return planOrderMapper.updateById(planOrder);
    }

    /**
     * 合并工单
     * @param planWorkOrders
     * @return
     */
    private List<PlanWorkOrder> mergeWorkOrder(List<PlanWorkOrder> planWorkOrders) {
        List<PlanWorkOrder> list = new ArrayList<>();

        Map<String,PlanWorkOrder> map = new LinkedHashMap<>();
        //合并
        for (PlanWorkOrder planWorkOrder : planWorkOrders) {
            PlanWorkOrder workOrder = map.get(planWorkOrder.getProductCode());
            if(workOrder == null){
                map.put(planWorkOrder.getProductCode(),planWorkOrder);
            }else {
                workOrder.setRequiredQty(workOrder.getRequiredQty() + planWorkOrder.getRequiredQty());
            }
        }
        //重新设置工单号
        for (String key : map.keySet()) {
            PlanWorkOrder workOrder = map.get(key);
            workOrder.setWorkOrderCode(workOrder.getOrderCode() + "-" + list.size() + 1);
            list.add(workOrder);
        }
        return list;
    }

    /**
     * 递归根据BOM生成工单
     * @param planWorkOrders
     * @param resources
     */
    public void generateWorkOrder(List<PlanWorkOrder> planWorkOrders, PlanOrderDto resources){
        //根据当前工单生成工单
        PlanWorkOrder workOrder = orderToWorkOrder(resources , planWorkOrders.size());
        planWorkOrders.add(workOrder);

        //根据产品获取BOM(启用的)
        ProductBom productBom = new ProductBom();
        productBom.setProductCode(resources.getProductCode());
        productBom.setIsDisable(DictValueEnum.START.getValue());
        ProductBom bom = productBomMapper.selectOne(new QueryWrapper<>(productBom));
        if(bom == null){
            return;
        }
        //获取BOM详情
        ProductBomDetail productBomDetail = new ProductBomDetail();
        productBomDetail.setBomId(bom.getId());
        List<ProductBomDetail> productBomDetails = productBomDetailMapper.selectList(new QueryWrapper<>(productBomDetail));
        if(productBomDetails == null){
            throw new RuntimeException("当前产品【"+resources.getProductCode()+"】未设置BOM明细，请设置后再试！");
        }
        //循环检测物料是否存在产品
        for (ProductBomDetail bomDetail : productBomDetails) {
            ProductModel productModel = new ProductModel();
            productModel.setMaterialCode(bomDetail.getMaterialCode());
            ProductModel product = productModelMapper.selectOne(new QueryWrapper<>(productModel));
            if(product != null){
                PlanOrderDto order = getNewOrder(product,bomDetail,resources);
                //递归获取
                generateWorkOrder(planWorkOrders, order);
            }
        }
    }

    public void generateWorkOrderSerial(){

    }

    /**
     * 根据父订单生成子订单
     * @param product
     * @param parentOrder
     * @return
     */
    private PlanOrderDto getNewOrder(ProductModel product, ProductBomDetail bomDetail ,PlanOrderDto parentOrder) {
        //深克隆
        PlanOrderDto planOrderDto = ObjectUtil.cloneByStream(parentOrder);

        planOrderDto.setProductCode(product.getProductCode());
        planOrderDto.setProductType(product.getProductType());

        //计算需求数量
        Integer quantity = bomDetail.getQuantity() == null ? 0 : bomDetail.getQuantity();
        Integer requiredQty = parentOrder.getRequiredQty() == null ? 0 : parentOrder.getRequiredQty();

        //计算损耗率
        BigDecimal attritionRate = bomDetail.getAttritionRate() == null ? new BigDecimal(0.0) : bomDetail.getAttritionRate() ;
        Integer totalQty = quantity * requiredQty;
        BigDecimal attrition = attritionRate.multiply(new BigDecimal(totalQty));
        attrition.setScale(1,BigDecimal.ROUND_CEILING);

        //设置需求数量
        planOrderDto.setRequiredQty(totalQty + attrition.intValue());

        return planOrderDto;
    }

    /**
     * 根据订单生产工单信息
     * @param resources
     * @return
     */
    private PlanWorkOrder orderToWorkOrder(PlanOrderDto resources,Integer size) {

        //获取产品的工段
        ProductModelLien productModelLien = new ProductModelLien();
        productModelLien.setLineCode(resources.getLineCode());
        productModelLien.setModelCode(resources.getProductCode());
        ProductModelLien modelLien = productModelLienMapper.selectOne(new QueryWrapper<>(productModelLien));

        PlanWorkOrder workOrder = new PlanWorkOrder();
        workOrder.setWorkOrderCode(resources.getOrderCode() + "-"+size);
        workOrder.setOrderCode(resources.getOrderCode());
        workOrder.setOrderStatus(DictValueEnum.WORK_STATUS_NOT.getValue());
        workOrder.setLineCode(resources.getLineCode());
        workOrder.setSectionCode(modelLien == null ? "" : modelLien.getSectionCode());
        workOrder.setProductCode(resources.getProductCode());
        workOrder.setProductType(resources.getProductType());
        workOrder.setRequiredQty(resources.getRequiredQty());
        workOrder.setOnlineQty(0);
        workOrder.setTotalQty(0);
        workOrder.setFailQty(0);
        workOrder.setFinishQty(0);
        workOrder.setUnfinishQty(0);
        workOrder.setScrapQty(0);
        workOrder.setClientName(resources.getClientName());
        workOrder.setPlanner(resources.getPlanner());
        workOrder.setPlanEnd(resources.getPlanEnd());
        workOrder.setPlanStart(resources.getPlanStart());
        workOrder.setRemark(resources.getRemark());
        return  workOrder;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int removeById(Integer id){
        Set<Integer> set = new HashSet<>(1);
        set.add(id);
        return this.removeByIds(set);
    }

    /*
    private void delCaches(Integer id) {
        redisUtils.delByKey(CACHE_KEY + "::id:", id);
    }

    private void delCaches(Set<Integer> ids) {
        for (Integer id: ids) {
            delCaches(id);
        }
    }*/

    /*
    @Override
    public void download(List<PlanOrderDto> all, HttpServletResponse response) throws IOException {
      List<Map<String, Object>> list = new ArrayList<>();
      for (PlanOrderDto planOrder : all) {
        Map<String,Object> map = new LinkedHashMap<>();
              map.put("订单编号", planOrder.getOrderCode());
              map.put("订单状态", planOrder.getOrderStatus());
              map.put("产品型号", planOrder.getProductCode());
              map.put("产品类型", planOrder.getProductType());
              map.put("需求数量", planOrder.getRequiredQty());
              map.put("产线编号", planOrder.getLineCode());
              map.put("计划开始", planOrder.getPlanStart());
              map.put("计划结束", planOrder.getPlanEnd());
              map.put("计划员", planOrder.getPlanner());
              map.put("客户名称", planOrder.getClientName());
              map.put("订单来源", planOrder.getOrderSorts());
              map.put("描述", planOrder.getRemark());
              map.put("创建人", planOrder.getCreateBy());
              map.put("创建时间", planOrder.getCreateTime());
              map.put("更新人", planOrder.getUpdateBy());
              map.put("更新时间", planOrder.getUpdateTime());
        list.add(map);
      }
      FileUtil.downloadExcel(list, response);
    }*/
}
